package com.gnerv.battle.boot.security.config;

import com.gnerv.battle.boot.security.autoconfigure.BattleSecurityConfigProperties;
import com.gnerv.battle.boot.security.service.AbstractUrlPermissionService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.function.Supplier;

/**
 * @author Gnerv LiGen
 */
@Component
public class BattleCustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Resource
    private BattleSecurityConfigProperties battleSecurityConfigProperties;

    private final AbstractUrlPermissionService urlPermissionService;

    public BattleCustomAuthorizationManager(AbstractUrlPermissionService urlPermissionService) {
        this.urlPermissionService = urlPermissionService;
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        HttpServletRequest httpServletRequest = requestAuthorizationContext.getRequest();
        // 获取请求路径和方法
        String requestUri = httpServletRequest.getRequestURI();
        // 判断地址是否是在排除
        for (String publicUrl : battleSecurityConfigProperties.getPublicUrl()) {
            boolean matcher = new AntPathRequestMatcher(publicUrl).matches(httpServletRequest);
            if (matcher) {
                return new AuthorizationDecision(true);
            }
        }
        // 获取请求方式
        String requestMethod = httpServletRequest.getMethod();
        // 通过请求地址和请求方式查询接口权限
        String permission = urlPermissionService.selectPermission(requestUri, requestMethod.toLowerCase());
        // 如果权限为 public 则为公开接口
        if (battleSecurityConfigProperties.getPublicPermission().equals(permission)) {
            return new AuthorizationDecision(true);
        }
        Authentication userAuthentication;
        try {
            // 获取登录用户
            userAuthentication = authentication.get();
        } catch (Exception exception) {
            throw new AccountExpiredException("");
        }
        String username = userAuthentication.getName();
        // 如果用户名为 admin 则默认有全部权限
        if (isSuperAdmin(username)) {
            return new AuthorizationDecision(true);
        }
        Collection<? extends GrantedAuthority> authorities = userAuthentication.getAuthorities();
        boolean verify = urlPermissionService.verify(authorities, permission);
        return new AuthorizationDecision(verify);
    }

    private boolean isSuperAdmin(String username) {
        return battleSecurityConfigProperties.getSuperAdmin().equals(username);
    }

}